package com.sinosoft.utils.finance;

import java.util.ArrayList;
import java.util.List;

/**
 * @Auther: zouren
 * @Date: 2019/4/23 17:15
 * @Description:
 */
public class Rate {
    /**
     * 实际利率法
     * @param a 现值
     * @param b 年金
     * @param c 期数
     * @param cnt 运算次数
     * @param ina 误差位数
     * @return 利率
     */
    public static double rate(double a,double b,double c,int cnt,int ina){
        double rate = 1,x,jd = 0.1,side = 0.1,i = 1;
        do{
            x = a/b - (Math.pow(1+rate, c)-1)/(Math.pow(rate+1, c)*rate);
            if(x*side>0){side = -side;jd *=10;}
            rate += side/jd;
        }while(i++<cnt&&Math.abs(x)>=1/Math.pow(10, ina));
        if(i>cnt)return Double.NaN;
        return rate;
    }


    /**迭代次数*/
    public static int LOOPNUM=1000;
    /**最小差异*/
    public static final double MINDIF=0.00000001;
    /**
     * @desc 使用方法参考main方法
     * @param cashFlow  资金流
     * @return 收益率
     */
    public static double getIrr(List<Double> cashFlow){
        double flowOut=cashFlow.get(0);
        double minValue=0d;
        double maxValue=1d;
        double testValue=0d;
        while(LOOPNUM>0){
            testValue=(minValue+maxValue)/2;
            double npv=NPV(cashFlow,testValue);
            if(Math.abs(flowOut+npv)<MINDIF){
                break;
            }else if(Math.abs(flowOut)>npv){
                maxValue=testValue;
            }else{
                minValue=testValue;
            }
            LOOPNUM--;
        }
        return testValue;
    }

    public static double NPV(List<Double> flowInArr,double rate){
        double npv=0;
        for(int i=1;i<flowInArr.size();i++){
            npv+=flowInArr.get(i)/Math.pow(1+rate, i);
        }
        return npv;
    }

    public static void main(String agrs[]) {

            Double 现值 = 7944760.00d;
            Double 年金 = 186627.21d;
            Double 期数 = 48d;

            //计算200次，比Excel20次要精确，误差精确到小数点后10位
            System.out.println(rate(现值,年金,期数,200,10));

        double flowOut=-237000d;
        List<Double> flowInArr=new ArrayList<Double>();
        flowInArr.add(flowOut);
        flowInArr.add(22643.999991d);
        flowInArr.add(22643.999991d);
        flowInArr.add(22643.999991d);
        flowInArr.add(22643.999991d);
        flowInArr.add(22643.999991d);
        flowInArr.add(22643.999991d);
        flowInArr.add(22643.999991d);
        flowInArr.add(22643.999991d);
        flowInArr.add(22643.999991d);
        flowInArr.add(22643.999991d);
        flowInArr.add(22643.999991d);
        flowInArr.add(22643.999991d);


        System.out.println(getIrr(flowInArr)*12);
    }

}
